跳至主要内容

深入理解 batch update 與 updater function

batch update

setState 的資料更新後會觸發 component re-render,react 會在將所有執行的事件完成後,才會進行 re-render。

在上面的例子中:

  1. react 執行 App compoent function 後會產生描述畫面的 React element ,並將這個 React element 產生相對應的 DOM element 渲染到瀏覽器上。

  2. 在 App component 中初始的 count state 是 0 ,clickCount state 是 0

  3. 當點擊 button 後會去執行 handleClick function

    • 當執行到 setCount(1)時,react 會將這個更新的動作依照順序放到一個代執行計算佇列 (queue)中

    • 此時的佇列依序由舊至新有:setCount(1)

    • 此時 count 的值為 0

    • 此時 clickCount 的值為 0

    • 當執行到 setCount(3)時,react 會將這個更新的動作放到佇列 (queue)中

    • 此時的佇列由舊至新依序有:setCount(1)setCount(3)

    • 此時 count 的值為 0

    • 此時 clickCount 的值為 0

    • 當執行到 setCount(5)時,react 會將這個更新的動作放到佇列 (queue)中

    • 此時的佇列由舊至新依序有:setCount(1)setCount(3)setCount(5)

    • 此時 count 的值為 0

    • 此時 clickCount 的值為 0

    • 當執行到 setClickCount((clickCount) => clickCount + 1)時,react 會將這個更新的動作放到佇列 (queue)中

    • 此時的佇列由舊至新依序有:setCount(1)setCount(3)setCount(5)、setClickCount((clickCount) => clickCount + 1)

    • 此時 count 的值為 0

    • 此時 clickCount 的值為 0

    • 執行完所有的事件後,react 會依照最新佇列的順序自動合併相同的 setState 方法,並且只執行最後一次的 setState 方法,

    • 此時 count 的值為 5,

    • 此時 clickCount 的值為 1

  4. 更新 state 後才會進行一次 re-render。

batch update 的機制就是 React 會自動將所有的 setState 方法依序合併成一次更新,藉此可以省去每更新一次 state 就進行一次 re-render 的效能問題,也可以避免半成品的資料進行 render。

flushSync api

大多數的情況下 react 都會自動幫我們處理好 setState 合併更新資料,但如果想要針對某些狀態需要當下就觀察到 DOM element 就可以使用 flushSync 方法,flushSync 可以指定某些 setState 方法不要 batch update,而是立刻 re-render。

但是使用 flushSync 需要注意的是 flushSync blocking 的,如果 DOM 處理太久會阻擋後續的畫面更新繼續進行,可能會造成畫面卡頓。

updater function

updater function 可以作為參數傳入 setState 方法。

const [count, setCount] = useState(0);
const handleClick = () => {
setCount((prevCount) => prevCount + 1);
//(prevCount) => prevCount + 1 就是 updater function
};

在這個例子中,updater function 會讓 setCount 根據到目前為止的 count 值 prevCount 去計算產生新的 count 值。

需要使用 updater function 的情境

  • 需要拿到當下 state 持續做計算
  • 可以在子元件中直接去拿到 state 的值